from flask import Flask, request, jsonify, send_file
from flask_cors import CORS
from minio import Minio
from minio.error import S3Error
import os
import uuid
import mimetypes
from datetime import datetime, timedelta
import logging
from config import config

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('database_backend.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# 创建Flask应用
app = Flask(__name__)

# 加载配置
config_name = os.getenv('FLASK_ENV', 'development')
app.config.from_object(config[config_name])

# 配置CORS
CORS(app, origins=app.config['CORS_ORIGINS'])

# MinIO配置
MINIO_ENDPOINT = app.config['MINIO_ENDPOINT']
MINIO_ACCESS_KEY = app.config['MINIO_ACCESS_KEY']
MINIO_SECRET_KEY = app.config['MINIO_SECRET_KEY']
MINIO_SECURE = app.config['MINIO_SECURE']

# 初始化MinIO客户端
try:
    minio_client = Minio(
        MINIO_ENDPOINT,
        access_key=MINIO_ACCESS_KEY,
        secret_key=MINIO_SECRET_KEY,
        secure=MINIO_SECURE
    )
    logger.info(f"MinIO客户端初始化成功: {MINIO_ENDPOINT}")
except Exception as e:
    logger.error(f"MinIO客户端初始化失败: {e}")
    minio_client = None

# 默认存储桶名称
DEFAULT_BUCKET = app.config['DEFAULT_BUCKET']

def ensure_bucket_exists(bucket_name):
    """确保存储桶存在，如果不存在则创建"""
    if not minio_client:
        return False
        
    try:
        if not minio_client.bucket_exists(bucket_name):
            minio_client.make_bucket(bucket_name)
            logger.info(f"创建存储桶: {bucket_name}")
        return True
    except S3Error as e:
        logger.error(f"创建存储桶失败: {e}")
        return False
    except Exception as e:
        logger.error(f"存储桶操作异常: {e}")
        return False

def validate_file_type(filename):
    """验证文件类型是否允许"""
    if '.' not in filename:
        return False
    ext = filename.rsplit('.', 1)[1].lower()
    return ext in app.config['ALLOWED_EXTENSIONS']

@app.route('/api/health', methods=['GET'])
def health_check():
    """健康检查接口"""
    try:
        if not minio_client:
            return jsonify({
                'status': 'unhealthy',
                'minio_connected': False,
                'error': 'MinIO客户端未初始化',
                'timestamp': datetime.now().isoformat()
            }), 500
            
        # 检查MinIO连接
        buckets = minio_client.list_buckets()
        return jsonify({
            'status': 'healthy',
            'minio_connected': True,
            'buckets_count': len(buckets),
            'minio_endpoint': MINIO_ENDPOINT,
            'timestamp': datetime.now().isoformat()
        })
    except Exception as e:
        logger.error(f"健康检查失败: {e}")
        return jsonify({
            'status': 'unhealthy',
            'minio_connected': False,
            'error': str(e),
            'timestamp': datetime.now().isoformat()
        }), 500

@app.route('/api/buckets', methods=['GET'])
def list_buckets():
    """获取所有存储桶列表"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        buckets = minio_client.list_buckets()
        bucket_list = []
        for bucket in buckets:
            try:
                # 获取存储桶中的对象数量
                objects = minio_client.list_objects(bucket.name, recursive=True)
                object_count = sum(1 for _ in objects)
                
                bucket_info = {
                    'name': bucket.name,
                    'creation_date': bucket.creation_date.isoformat(),
                    'object_count': object_count
                }
                bucket_list.append(bucket_info)
            except Exception as e:
                logger.warning(f"获取存储桶 {bucket.name} 信息失败: {e}")
                bucket_info = {
                    'name': bucket.name,
                    'creation_date': bucket.creation_date.isoformat(),
                    'object_count': 0
                }
                bucket_list.append(bucket_info)
        
        return jsonify({
            'success': True,
            'buckets': bucket_list,
            'count': len(bucket_list)
        })
    except S3Error as e:
        logger.error(f"获取存储桶列表失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"获取存储桶列表异常: {e}")
        return jsonify({
            'success': False,
            'error': '服务器内部错误'
        }), 500

@app.route('/api/buckets', methods=['POST'])
def create_bucket():
    """创建存储桶"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        data = request.get_json()
        if not data:
            return jsonify({
                'success': False,
                'error': '请求数据不能为空'
            }), 400
            
        bucket_name = data.get('name')
        if not bucket_name:
            return jsonify({
                'success': False,
                'error': '存储桶名称不能为空'
            }), 400
        
        # 验证存储桶名称
        if not bucket_name.replace('-', '').replace('.', '').isalnum():
            return jsonify({
                'success': False,
                'error': '存储桶名称只能包含字母、数字、连字符和点'
            }), 400
        
        if minio_client.bucket_exists(bucket_name):
            return jsonify({
                'success': False,
                'error': '存储桶已存在'
            }), 400
        
        minio_client.make_bucket(bucket_name)
        logger.info(f"创建存储桶: {bucket_name}")
        
        return jsonify({
            'success': True,
            'message': f'存储桶 {bucket_name} 创建成功',
            'bucket_name': bucket_name
        })
    except S3Error as e:
        logger.error(f"创建存储桶失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"创建存储桶异常: {e}")
        return jsonify({
            'success': False,
            'error': '服务器内部错误'
        }), 500

@app.route('/api/files/upload', methods=['POST'])
def upload_file():
    """上传文件"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        if 'file' not in request.files:
            return jsonify({
                'success': False,
                'error': '没有选择文件'
            }), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({
                'success': False,
                'error': '文件名为空'
            }), 400
        
        # 验证文件类型
        if not validate_file_type(file.filename):
            return jsonify({
                'success': False,
                'error': f'不支持的文件类型，允许的类型: {", ".join(app.config["ALLOWED_EXTENSIONS"])}'
            }), 400
        
        # 获取存储桶名称，默认为source-data
        bucket_name = request.form.get('bucket', DEFAULT_BUCKET)
        
        # 确保存储桶存在
        if not ensure_bucket_exists(bucket_name):
            return jsonify({
                'success': False,
                'error': '无法创建存储桶'
            }), 500
        
        # 使用原始文件名，如果存在同名文件则添加时间戳
        original_filename = file.filename
        file_extension = os.path.splitext(original_filename)[1]
        base_name = os.path.splitext(original_filename)[0]
        
        # 检查文件是否已存在
        try:
            minio_client.stat_object(bucket_name, original_filename)
            # 文件已存在，添加时间戳
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            unique_filename = f"{base_name}_{timestamp}{file_extension}"
        except S3Error:
            # 文件不存在，使用原始文件名
            unique_filename = original_filename
        
        # 获取文件内容类型
        content_type = file.content_type or mimetypes.guess_type(file.filename)[0] or 'application/octet-stream'
        
        # 上传文件到MinIO
        # 读取文件内容到内存
        file_data = file.read()
        file_size = len(file_data)
        
        logger.info(f"文件大小: {file_size} 字节")
        
        # 使用BytesIO包装文件数据
        from io import BytesIO
        file_obj = BytesIO(file_data)
        
        # 上传到MinIO
        result = minio_client.put_object(
            bucket_name,
            unique_filename,
            file_obj,
            file_size,
            content_type=content_type
        )
        
        logger.info(f"文件上传成功: {unique_filename}, 大小: {file_size}")
        
        return jsonify({
            'success': True,
            'message': '文件上传成功',
            'file_info': {
                'original_name': original_filename,
                'stored_name': unique_filename,
                'bucket': bucket_name,
                'size': file_size,
                'content_type': content_type,
                'upload_time': datetime.now().isoformat()
            }
        })
    except S3Error as e:
        logger.error(f"文件上传失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"文件上传异常: {e}")
        import traceback
        logger.error(f"异常详情: {traceback.format_exc()}")
        return jsonify({
            'success': False,
            'error': f'文件上传失败: {str(e)}'
        }), 500

@app.route('/api/files/<bucket_name>', methods=['GET'])
def list_files(bucket_name):
    """获取存储桶中的文件列表"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        if not minio_client.bucket_exists(bucket_name):
            return jsonify({
                'success': False,
                'error': '存储桶不存在'
            }), 404
        
        objects = minio_client.list_objects(bucket_name, recursive=True)
        file_list = []
        
        for obj in objects:
            file_info = {
                'name': obj.object_name,
                'size': obj.size,
                'last_modified': obj.last_modified.isoformat(),
                'etag': obj.etag,
                'content_type': obj.content_type
            }
            file_list.append(file_info)
        
        return jsonify({
            'success': True,
            'files': file_list,
            'count': len(file_list),
            'bucket': bucket_name
        })
    except S3Error as e:
        logger.error(f"获取文件列表失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"获取文件列表异常: {e}")
        return jsonify({
            'success': False,
            'error': '服务器内部错误'
        }), 500

@app.route('/api/files/download/<bucket_name>/<path:file_name>', methods=['GET'])
def download_file(bucket_name, file_name):
    """下载文件"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        if not minio_client.bucket_exists(bucket_name):
            return jsonify({
                'success': False,
                'error': '存储桶不存在'
            }), 404
        
        # 获取文件对象
        response = minio_client.get_object(bucket_name, file_name)
        
        # 获取文件信息
        stat = minio_client.stat_object(bucket_name, file_name)
        
        return send_file(
            response,
            as_attachment=True,
            download_name=file_name,
            mimetype=stat.content_type
        )
    except S3Error as e:
        logger.error(f"文件下载失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"文件下载异常: {e}")
        return jsonify({
            'success': False,
            'error': '文件下载失败'
        }), 500

@app.route('/api/files/<bucket_name>/<path:file_name>', methods=['DELETE'])
def delete_file(bucket_name, file_name):
    """删除文件"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        if not minio_client.bucket_exists(bucket_name):
            return jsonify({
                'success': False,
                'error': '存储桶不存在'
            }), 404
        
        minio_client.remove_object(bucket_name, file_name)
        logger.info(f"文件删除成功: {file_name}")
        
        return jsonify({
            'success': True,
            'message': f'文件 {file_name} 删除成功'
        })
    except S3Error as e:
        logger.error(f"文件删除失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"文件删除异常: {e}")
        return jsonify({
            'success': False,
            'error': '文件删除失败'
        }), 500

@app.route('/api/files/presigned-url/<bucket_name>/<path:file_name>', methods=['GET'])
def get_presigned_url(bucket_name, file_name):
    """获取预签名URL（用于临时访问）"""
    try:
        if not minio_client:
            return jsonify({
                'success': False,
                'error': 'MinIO客户端未初始化'
            }), 500
            
        if not minio_client.bucket_exists(bucket_name):
            return jsonify({
                'success': False,
                'error': '存储桶不存在'
            }), 404
        
        # 生成7天有效的预签名URL
        url = minio_client.presigned_get_object(
            bucket_name, 
            file_name, 
            expires=timedelta(days=7)
        )
        
        return jsonify({
            'success': True,
            'url': url,
            'expires_in_days': 7
        })
    except S3Error as e:
        logger.error(f"生成预签名URL失败: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500
    except Exception as e:
        logger.error(f"生成预签名URL异常: {e}")
        return jsonify({
            'success': False,
            'error': '生成访问链接失败'
        }), 500

@app.errorhandler(404)
def not_found(error):
    return jsonify({
        'success': False,
        'error': '接口不存在'
    }), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({
        'success': False,
        'error': '服务器内部错误'
    }), 500

@app.errorhandler(413)
def too_large(error):
    return jsonify({
        'success': False,
        'error': '文件过大，最大支持100MB'
    }), 413

if __name__ == '__main__':
    # 确保默认存储桶存在
    if minio_client:
        ensure_bucket_exists(DEFAULT_BUCKET)
    
    # 启动Flask应用
    app.run(
        host='0.0.0.0',
        port=5000,
        debug=app.config['DEBUG']
    )

